//
// Game Animation.
// Copyright (C) 2007 Department of Computer Science, University of Copenhagen
//
#include <animation/configuration.h>

#define DEFINE_GLUT_MAIN
#include <OpenTissue/utility/glut/glut_perspective_view_application.h>
#undef DEFINE_GLUT_MAIN


#include <OpenTissue/utility/gl/gl_util.h>
#include <OpenTissue/gpu/cg/cg_util.h>

#include <OpenTissue/gpu/image/image.h>
#include <OpenTissue/gpu/image/image_make_noise.h>
#include <OpenTissue/gpu/image/image_make_fractal_sum_noise.h>
#include <OpenTissue/gpu/image/image_make_fractal_sum_abs_noise.h>
#include <OpenTissue/gpu/image/image_animate_turbulence.h>

#include <animation/game_animation_types.h>
#include "animate_clouds.h"

#include <boost/shared_ptr.hpp>
class Straw{
public:
	int r;
	int g;
	int b;
	int a;
	int x;
	int y;
	Straw():a(0),r(0),b(0),g(0){}
};
class Application : public OpenTissue::glut::PerspectiveViewApplication
{
public:

  typedef animation::GameAnimationTypes< OpenTissue::math::BasicMathTypes<float,size_t>  >       types;
  typedef types::real_type                  real_type;
  typedef types::vector3_type                vector3_type;
  typedef OpenTissue::image::Image<real_type>        image_type;
  typedef OpenTissue::image::Image<unsigned char>        cimage_type;
  typedef boost::shared_ptr<image_type >    image_pointer;

protected:

  image_pointer                             m_ptr_image;
  image_type                             m_image;
  real_type                                 m_time;

public:

  Application()
  {
    //--- This is how one could change the default size of the main window
    this->width() = 512;
    this->height() = 512;
  }

public:

  char const * do_get_title() const { return "Game Animation Noise Demo Application"; }

  void do_display()
  {
    OpenTissue::gl::gl_check_errors("start dispaly");
    glPushMatrix();
    OpenTissue::gl::Transform(
      math_types::vector3_type(-(m_image.width()*.5),-(m_image.height()*.5),0.0)
      );
    OpenTissue::gl::DrawImage(m_image);
    glPopMatrix();

  }

  void do_action(unsigned char /*choice*/){}

  void do_init_right_click_menu(int /*main_menu*/, void /*menu*/(int entry)){}

  void do_init()
  {
    OpenTissue::cg::startup();

    m_image.create(256,256,1);

    //make_noise(m_image,16,1);
	
    make_fractal_sum_noise(m_image,16.0,0.5,4);
    //make_fractal_sum_abs_noise(m_image,4.0,0.5,8);
    //animate_turbulence(m_image,0.0,4.0,0.5,32);
	//OpenTissue::animate_clouds(m_image,1);
	
    m_time = 0.0;

	unsigned char*  data=new unsigned char[4*this->width()*this->height()];
	const unsigned int s=1000;
	Straw straws[s];
	for(int p=0;p<this->width();p++){
		for(int q=0;q<this->height();q++){
			data[q*this->width()+p]=0;
		}
	}

	srand(100);
    unsigned int i=0;
	while(i<s){
		while(true){
			int x=rand()%506+3;
			int y=rand()%506+3;
			bool succeded=true;
			for(unsigned int j=0;j<i;j++){
				if(x<straws[j].x+4&&
				   x>straws[j].x-4&&
				   y<straws[j].y+4&&
				   y>straws[j].y-4
				   ){
					   succeded=false;
				}
			}
			if(succeded){
				straws[i].x=x;
				straws[i].y=y;
				straws[i].r=rand()%55+5;
			    straws[i].g=rand()%55+200;
			    straws[i].b=rand()%55+82;
			    straws[i].a=rand()%150+40;
				break;
			}
		}
		paint(data,0,straws[i].g,0,straws[i].a,straws[i].x-3,straws[i].y+2);
		paint(data,0,straws[i].g-15,0,straws[i].a,straws[i].x-3,straws[i].y+1);
		paint(data,0,straws[i].g-5,0,straws[i].a,straws[i].x-3,straws[i].y);

		paint(data,0,straws[i].g,0,straws[i].a,straws[i].x-2,straws[i].y+1);
		paint(data,0,straws[i].g-15,0,straws[i].a,straws[i].x-2,straws[i].y);

		paint(data,0,straws[i].g,0,straws[i].a,straws[i].x-1,straws[i].y+1);
		paint(data,0,straws[i].g-15,0,straws[i].a,straws[i].x-1,straws[i].y);
		paint(data,0,straws[i].g-15,0,straws[i].a,straws[i].x-1,straws[i].y-1);

		paint(data,0,straws[i].g-10,0,straws[i].a,straws[i].x,straws[i].y-1);
		paint(data,0,straws[i].g,0,straws[i].a,straws[i].x,straws[i].y);

		paint(data,0,straws[i].g+10,0,straws[i].a,straws[i].x+1,straws[i].y+1);
		paint(data,0,straws[i].g-10,0,straws[i].a,straws[i].x+1,straws[i].y);
		paint(data,0,straws[i].g-10,0,straws[i].a,straws[i].x+1,straws[i].y-1);

		paint(data,0,straws[i].g+10,0,straws[i].a,straws[i].x+2,straws[i].y+1);
		paint(data,0,straws[i].g-10,0,straws[i].a,straws[i].x+2,straws[i].y);

		paint(data,0,straws[i].g+10,0,straws[i].a,straws[i].x+3,straws[i].y+2);
		paint(data,0,straws[i].g-10,0,straws[i].a,straws[i].x+3,straws[i].y+1);
		paint(data,0,straws[i].g-10,0,straws[i].a,straws[i].x+3,straws[i].y);


		/*
		paint(data,straws[i].r,straws[i].g,straws[i].b,straws[i].a,straws[i].x,straws[i].y-2);
		paint(data,straws[i].r,straws[i].g,straws[i].b,straws[i].a,straws[i].x-1,straws[i].y-1);
		paint(data,straws[i].r,straws[i].g,straws[i].b,straws[i].a,straws[i].x,straws[i].y-1);
		paint(data,straws[i].r,straws[i].g,straws[i].b,straws[i].a,straws[i].x+1,straws[i].y-1);
		paint(data,straws[i].r,straws[i].g,straws[i].b,straws[i].a,straws[i].x-2,straws[i].y);
		paint(data,straws[i].r,straws[i].g,straws[i].b,straws[i].a,straws[i].x-1,straws[i].y);
		paint(data,straws[i].r,straws[i].g,straws[i].b,straws[i].a,straws[i].x,straws[i].y);
		paint(data,straws[i].r,straws[i].g,straws[i].b,straws[i].a,straws[i].x+1,straws[i].y);
		paint(data,straws[i].r,straws[i].g,straws[i].b,straws[i].a,straws[i].x+2,straws[i].y);
		paint(data,straws[i].r,straws[i].g,straws[i].b,straws[i].a,straws[i].x,straws[i].y+2);
		paint(data,straws[i].r,straws[i].g,straws[i].b,straws[i].a,straws[i].x-1,straws[i].y+1);
		paint(data,straws[i].r,straws[i].g,straws[i].b,straws[i].a,straws[i].x,straws[i].y+1);
		paint(data,straws[i].r,straws[i].g,straws[i].b,straws[i].a,straws[i].x+1,straws[i].y+1);
		*/
		i++;
	}      
	cimage_type img(this->width(), this->height(),4,data);
	OpenTissue::image::write("grass.png",img);

	delete[] data;
  }
  void paint(unsigned char* &data,unsigned int r,unsigned int g,unsigned int b,unsigned int a,unsigned int x,unsigned int y){
     unsigned int index=y*this->width()*4+4*x;
	 data[index]=r;
	 data[index+1]=g;
	 data[index+2]=b;
	 data[index+3]=a;
  }
  void do_run()
  {
    //animate_turbulence(m_image,m_time,4.0,0.5,8);
	//OpenTissue::animate_clouds(m_image,m_time,4.0,0.125,8);
    m_time += 0.01;
  }

  void do_shutdown()
  {
    OpenTissue::cg::shutdown();
  }

};

OpenTissue::glut::instance_pointer init_glut_application(int /*argc*/, char ** /*argv*/)
{
  OpenTissue::glut::instance_pointer instance;
  instance.reset( new Application() );
  return instance;
}
